package org.sample.springbootdatabase.web;

import org.sample.springbootdatabase.domain.entity.User;
import org.sample.springbootdatabase.service.DatabaseUserService;
import org.sample.springbootdatabase.web.model.DateDTO;
import org.sample.springbootdatabase.web.model.UserDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@EnableAutoConfiguration
@RequestMapping("/user")
public class UserController {

	private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);

	@Autowired
	private DatabaseUserService service;
	
	@GetMapping("/all")
	public List<UserDTO> findAll() {
		return service.findAllUsers().stream()
				.map(this::buildUserDTO).collect(Collectors.toList());
	}

	@GetMapping("/{id}")
	public ResponseEntity<UserDTO> findById(@PathVariable("id") Long id) {
		if (id != null) {
			UserDTO userDTO = buildUserDTO(service.findUserById(id));
			return ResponseEntity.ok().body(userDTO);
		} else {
			return ResponseEntity.notFound().build();
		}
	}

	@GetMapping
	public ResponseEntity<UserDTO> findByUserName(@RequestParam("username") String userName) {
		if (!StringUtils.isEmpty(userName)) {
			UserDTO userDTO = buildUserDTO(service.findUserByName(userName));
			return ResponseEntity.ok().body(userDTO);
		} else {
			return ResponseEntity.notFound().build();
		}
	}

	@PostMapping
	public UserDTO create(@RequestBody UserDTO userDTO) {
		return buildUserDTO(service.createUser(userDTO));
	}

	@PostMapping("/rollback")
	public UserDTO saveWithRollback(@RequestBody UserDTO userDTO) {
		return buildUserDTO(service.createUserWithRollback(userDTO));
	}

	@PostMapping("/norollback")
	public UserDTO saveWithoutRollback(@RequestBody UserDTO userDTO) {
		return buildUserDTO(service.createUserWithoutRollback(userDTO));
	}

	@PutMapping("/{id}")
	public UserDTO updateById(@PathVariable("id") Long id, @RequestBody UserDTO userDTO) {
		User user = buildUser(userDTO);
		if (user != null) {
			user.setId(id);
		}
		return buildUserDTO(service.updateUserById(user));
	}
	
	@PutMapping
	public UserDTO updateByName(@RequestParam("username") String userName, @RequestBody UserDTO userDTO) {
		return buildUserDTO(service.updateUserByName(userDTO));
	}

	@DeleteMapping("/{id}")
	public void deleteById(@PathVariable("id") Long id) {
		service.deleteUserById(id);
	}
	
	@DeleteMapping
	public void deleteByName(@RequestParam("username") String userName) {
		service.deleteUserByName(userName);
	}

	@PostMapping("/date")
	public List<UserDTO> findByCreatedDate(@RequestBody DateDTO dateDTO) {
		try {
			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
			List<User> users = service.findByCreatedDate(dateFormat.parse(dateDTO.getDate()));
			return users.stream().map(this::buildUserDTO).collect(Collectors.toList());
		} catch (ParseException ex) {
			LOGGER.error("Get user by created date failed", ex);
			return Collections.emptyList();
		}
	}

	private User buildUser(UserDTO userDTO) {
		if (userDTO == null) {
			return null;
		}
		
		User user = new User();
		user.setUserName(userDTO.getUserName());
		user.setFirstName(userDTO.getFirstName());
		user.setLastName(userDTO.getLastName());
		return user;
	}

	private UserDTO buildUserDTO(User user) {
		if (user == null) {
			return null;
		}
		
		UserDTO userDTO = new UserDTO();
		userDTO.setId(user.getId());
		userDTO.setUserName(user.getUserName());
		userDTO.setFirstName(user.getFirstName());
		userDTO.setLastName(user.getLastName());
		
		userDTO.setCreateDateTime(user.getCreatedDate().toString());
		userDTO.setLastAccessDateTime(user.getLastAccessed().toString());
		
		return userDTO;
	}

}
